<html>
<head>
  <title>Evernote Export</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/603932 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="1007"/>

<div>
<span><div><span style="font-size: unset; color: unset; font-family: unset;">1.概念：AQS是用来构建锁或者其他同步器组件的重量级基础框架及整个JUC体系的基石，通过内置的FIFO队列来</span><span style="font-size: unset; color: unset; font-family: unset;">完成资源获取线程的排队工作，并通过一个int类型变量表示持有锁的状态。</span></div><div><img src="AQS_files/Image.png" type="image/png" data-filename="Image.png"/></div><div>2.功能：规范锁的抢占，加锁会导致阻塞，AQS用来管理排队等候，和锁的分配。</div><div><img src="AQS_files/Image [1].png" type="image/png" data-filename="Image.png"/></div><div><br/></div><div><img src="AQS_files/Image [2].png" type="image/png" data-filename="Image.png"/></div><div><br/></div><div>3.实现：AQS使用一个volatile的int类型的成员变量来表示同步状态，通过内置的FIFO队列来完成资源获取的排队工作将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配，通过CAS完成对State值的修改</div><div><br/></div><div><img src="AQS_files/Image [3].png" type="image/png" data-filename="Image.png"/></div><div><br/></div><div><img src="AQS_files/Image [4].png" type="image/png" data-filename="Image.png"/></div><div><br/></div><div>4.公平锁与非公平锁的区别：公平锁判断了队列中是否有正在等待的线程，先进先出原则让等待更久的线程优先抢占锁。</div><div><br/></div><div><img src="AQS_files/Image [5].png" type="image/png" data-filename="Image.png"/></div><div><br/></div><div><br/></div><div><img src="AQS_files/Image [6].png" type="image/png" data-filename="Image.png"/></div><div><br/></div><div>5.ReentrantLock执行流程：</div><div>模拟银行办业务，假设有三个线程....</div><div>    (1)线程A，第一个获取锁，此时state=0，代表没有人占用锁，通过CAS将state 改为1.</div><div>    (2)线程B，第二个获取锁，此时state=1，代表有线程正占用锁，CAS修改state失败进入acquire()方法</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.15);-en-codeblock:true;"><div>final void lock() {</div><div>    if (<font color="#FF0000">compareAndSetState(0, 1)</font>)</div><div>        setExclusiveOwnerThread(Thread.currentThread());</div><div>    else</div><div>        <font color="#FF0000">acquire(1);</font></div><div>}</div></div><div>    (3)线程B，首先进入<span style="color: rgb(255, 0, 0);">tryAcquire(arg)</span>方法<span style="color: rgb(255, 0, 0);">，</span>再次判断是否有线程占用锁，如果没有人占用锁就占用。或者抢占锁的线程正是占用锁的线程（可重入锁）。此时线程A正在占用锁，因此返回false，取反为true，继续往下走</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.15);-en-codeblock:true;"><div>public final void acquire(int arg) {</div><div>    if (!<font style="color: rgb(255, 0, 0);">tryAcquire(arg)</font> &amp;&amp;</div><div>        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))</div><div>        selfInterrupt();</div><div>}</div></div><div>    (4)线程B，准备进入队列，此时队列尾为null，进入enq(node);方法，此时尾为null，创建一个空node节点作为哨兵节点，再将线程B加到哨兵节点后，将线程B的前节点指向哨兵节点，哨兵节点的后节点指向线程B，此时线程B已经进入队列。</div><div>    (5)线程C，准备进入队列，此时队列尾是线程B，将线程C的前节点指向线程B，线程B的后节点指向线程C，此时线程C进入队列</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.15);-en-codeblock:true;"><div>private Node addWaiter(Node mode) {</div><div>    Node node = new Node(Thread.currentThread(), mode);</div><div>    // Try the fast path of enq; backup to full enq on failure</div><div>    Node pred = tail;</div><div>    if (pred != null) {</div><div>        node.prev = pred;</div><div>        if (compareAndSetTail(pred, node)) {</div><div>            pred.next = node;</div><div>            return node;</div><div>        }</div><div>    }</div><div>   <font color="#FF0000"> enq(node);</font></div><div>    return node;</div><div>}</div><div><br/></div><div>private Node enq(final Node node) {</div><div>    for (;;) {</div><div>        Node t = tail;</div><div>        if (t == null) { // Must initialize</div><div>            //创建哨兵节点</div><div>            if (<font color="#FF0000">compareAndSetHead(new Node())</font>)</div><div>                tail = head;</div><div>        } else {</div><div>            node.prev = t;</div><div>            if (compareAndSetTail(t, node)) {</div><div>                t.next = node;</div><div>                return t;</div><div>            }</div><div>        }</div><div>    }</div><div>}</div></div><div>    (6)线程B，进入acquireQueued方法，此时B线程的前置节点为哨兵节点，它指向head，所以B可以继续抢占锁，线程B没抢到，进入<span style="color: rgb(255, 0, 0);">shouldParkAfterFailedAcquire(p, node)</span>方法，如果哨兵节点（当前线程的前驱节点）waitStatus不等于-1，就改为-1，返回false。再次循环，此时等于-1，返回true。进入parkAndCheckInterrupt()方法，线程B被挂起</div><div>    (7)线程C，如上过程（由于前节点不是哨兵节点，所以不能尝试抢占锁）。</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.15);-en-codeblock:true;"><div>final boolean acquireQueued(final Node node, int arg) {</div><div>    boolean failed = true;</div><div>    try {</div><div>        boolean interrupted = false;</div><div>        for (;;) {</div><div>            //返回前置节点</div><div>            final Node p = <font color="#FF0000">node.predecessor();</font></div><div>            if (p == head &amp;&amp; tryAcquire(arg)) {</div><div>                setHead(node);</div><div>                p.next = null; // help GC</div><div>                failed = false;</div><div>                return interrupted;</div><div>            }</div><div>            </div><div>            if (<font style="color: rgb(255, 0, 0);">shouldParkAfterFailedAcquire(p, node)</font> &amp;&amp;</div><div>                parkAndCheckInterrupt())</div><div>                interrupted = true;</div><div>        }</div><div>    } finally {</div><div>        if (failed)</div><div>            cancelAcquire(node);</div><div>    }</div><div>}</div><div><br/></div><div><br/></div><div>private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {</div><div>    int ws = pred.waitStatus;</div><div>    if (ws == Node.SIGNAL)</div><div>        return true;</div><div>    if (ws &gt; 0) {</div><div>        do {</div><div>            node.prev = pred = pred.prev;</div><div>        } while (pred.waitStatus &gt; 0);</div><div>        pred.next = node;</div><div>    } else {</div><div>        compareAndSetWaitStatus(pred, ws, Node.SIGNAL);</div><div>    }</div><div>    return false;</div><div>}</div><div><br/></div><div>private final boolean parkAndCheckInterrupt() {</div><div>    LockSupport.park(this);</div><div>    return Thread.interrupted();</div><div>}</div></div><div><br/></div><div><img src="AQS_files/Image [7].png" type="image/png" data-filename="Image.png"/></div><div>    (8)线程A，假如此时完成业务，开始释放锁，进入tryRelease(int releases)，执行setExclusiveOwnerThread(null);将当前工作中线程置为null，执行setState(c);将state=0；</div><div><span>    (9)此时</span>waitStatus = -1；执行unpark将h结束挂起；<br/></div><div><span>    (10)此时</span>acquireQueued被挂起的方法继续执行，将B线程加入工作线程，头节点指向B线程节点，将B线程节点置空，并且将哨兵节点指向null(等待垃圾回收器回收)；此时原来的B线程节点就变成了哨兵节点；<br/></div><div><span>    </span>(11)C线程节点的过程如上所述。</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.15);-en-codeblock:true;"><div>public final boolean release(int arg) {</div><div>    if (tryRelease(arg)) {</div><div>        Node h = head;</div><div>        if (h != null &amp;&amp; h.waitStatus != 0)</div><div>            unparkSuccessor(h);</div><div>        return true;</div><div>    }</div><div>    return false;</div><div>}</div><div><br/></div><div>protected final boolean tryRelease(int releases) {</div><div>    int c = getState() - releases;</div><div>    if (Thread.currentThread() != getExclusiveOwnerThread())</div><div>        throw new IllegalMonitorStateException();</div><div>    boolean free = false;</div><div>    if (c == 0) {</div><div>        free = true;</div><div>        setExclusiveOwnerThread(null);</div><div>    }</div><div>    setState(c);</div><div>    return free;</div><div>}</div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></span>
</div></body></html> 